package com.ossean.match.lucene;

import java.io.IOException;
import java.nio.file.Paths;
import java.sql.SQLException;
import java.util.List;

import javax.annotation.Resource;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.document.Field.Store;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.wltea.analyzer.lucene.IKAnalyzer;

import com.ossean.match.dao.ProjectDao;
import com.ossean.match.dao.RelativeMemoDao;
import com.ossean.match.matchprocess.MatchIncrement;
import com.ossean.match.model.Project;
import com.ossean.match.model.RelativeMemo;
import com.ossean.match.utils.Normalizer;

@Component("luceneindex")
public class LuceneIndex {
	
	private Logger logger = LoggerFactory.getLogger(LuceneIndex.class);
	public static final String MEMOS_INDEX_PATH = "memosLuceneIndex";
	public static final String PRJS_INDEX_PATH = "prjsLuceneIndex";
	public static String contentFieldName = "memoContent";
	public static String experienceFieldName = "experience";
	public static String salaryFieldName = "salary";
	public static String addrFieldName = "addr";
	public static String memoIdFieldName = "postId";
	public static String prjIdFieldName = "prjId";
	public static String prjNameFieldName = "prjName";
	public static String prjTagsFieldName = "prjTags";
	private int step = 100000;
	@Resource
	private RelativeMemoDao memoDao;
	@Resource
	private ProjectDao projectDao;
	
	public void run(MatchIncrement matchIncrement) {
		logger.info("start creating index!!!");
		long start = System.currentTimeMillis();
		Analyzer ikanalyzer = new IKAnalyzer(true);
		try {
			createPostIndex(ikanalyzer, matchIncrement);
			createPrjIndex(ikanalyzer, matchIncrement);
		} catch (IOException e) {
			logger.error("IOException: " + e);
		}
		long end = System.currentTimeMillis();
		logger.info("createIndex time: " + (end - start) / 1000 + "s");
	}

	public IndexWriter createIndexWriter(String indexPath, Analyzer analyzer)
			throws IOException {
		Directory dire = FSDirectory.open(Paths.get(indexPath));
		IndexWriterConfig iwc = new IndexWriterConfig(analyzer);
		iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
		IndexWriter iw = new IndexWriter(dire, iwc);
		return iw;
	}
	

	   /**
	    * creating projects index, usually, we need not use this method, 
	    * because projects index will create by increment during matching process
	    * @param conn
	    * @param analyzer
	    * @throws IOException
	    */
	public void createPrjIndex(Analyzer analyzer, MatchIncrement matchIncrement)
			throws IOException {
		int startId = 0;
		int endId = startId + step;
		IndexWriter writer = createIndexWriter(PRJS_INDEX_PATH, analyzer);
		int maxPrjId = projectDao.getNewLast();
		while (startId < maxPrjId) {
			try {
				List<Project> projects = projectDao.getBatchPrjs(startId, endId);
				for(Project project : projects) {
					if (project.getName() == null) {
						continue;
					}
					Document doc = new Document();
					doc.add(new StringField(prjIdFieldName, String.valueOf(project.getId()), Store.YES));
					String prjName = project.getName();
					Field prjNameField = new TextField(prjNameFieldName, prjName, Store.YES);
					if (prjName.getBytes().length == prjName.length() && prjName.replaceAll("\\d+"," ").indexOf(" ") == -1) {
						prjNameField.setBoost(6.0f);
					}
					doc.add(prjNameField);
					String prjTagsString = project.getTags();
					if (prjTagsString == null) {
						prjTagsString = "";
					}
					List<String> prjTagsList = Normalizer.tagsSegmentation(prjTagsString.toLowerCase());
					for(String prjTag : prjTagsList){
						doc.add(new StringField(prjTagsFieldName, prjTag, Store.NO));
					}
					writer.addDocument(doc);
				}
				logger.info("lucene indexed osps: "+ startId + "-->"+ endId);
			} catch (IOException e) {
				logger.error("createPrjIndex IOException: " + e);
			}
			if ((maxPrjId - endId) <= step) {
				startId = endId;
				endId = maxPrjId;
			}
			else {
				startId = endId;
				endId += step;
			}
		}
		matchIncrement.setCurrentProject(0);
		matchIncrement.setCurrentPrjIndexed(maxPrjId);
		matchIncrement.writeIntoRecord();
		writer.commit();
		writer.close();
	}

	/**
	 * creating post index
	 * @param conn
	 * @param analyzer
	 * @throws IOException
	 */
	public void createPostIndex(Analyzer analyzer, MatchIncrement matchIncrement)
			throws IOException {
		int startId = 0;
		int endId = startId + step;
		int lastMemoId=0;
		IndexWriter indexWriter = createIndexWriter(MEMOS_INDEX_PATH, analyzer);
		int maxMemoId = memoDao.getLastMemoId();
		while (startId < maxMemoId) {
			try {
				List<RelativeMemo> memos = memoDao.getMemoInfo(startId, endId);
				for(RelativeMemo memo : memos) {
					lastMemoId = memo.getId();
					if (memo.getContent() == null) {
						continue;
					}
					Document doc = new Document();
					if (memo.getExperience() == null) {
						memo.setExperience("");
					}
					if (memo.getSalary() == null) {
						memo.setSalary("");
					}
					if (memo.getAddr() == null) {
						memo.setAddr("");
					}
					doc.add(new StringField(memoIdFieldName, String.valueOf(lastMemoId), Store.YES));
					doc.add(new TextField(contentFieldName, memo.getContent(), Store.NO));
					doc.add(new StringField(experienceFieldName, memo.getExperience(), Store.YES));
					doc.add(new StringField(salaryFieldName, memo.getSalary(), Store.YES));
					doc.add(new StringField(addrFieldName, memo.getAddr(), Store.YES));
					indexWriter.addDocument(doc);
				}
				logger.info("lucene indexed relative_memos: "+ startId + "-->"+ endId);
			} catch (IOException e) {
				logger.error("createPostIndex IOException: " + e);
			}
			if ((maxMemoId - endId) <= step) {
				startId = endId;
				endId = maxMemoId;
			}
			else {
				startId = endId;
				endId += step;
			}
		}
		matchIncrement.setCurrentProject(0);
		matchIncrement.setCurrentMemo(lastMemoId);
		matchIncrement.setCurrentMemoIndexed(lastMemoId);
		matchIncrement.writeIntoRecord();
		/*FileOutputStream fout = new FileOutputStream(new File("record.txt"));
		fout.write((0 + "\t" + lastMemoId + "\t" + 0 + "\t" + 0).getBytes());  //初始化record.txt，项目初始id为0，帖子初始id为创建索引的最后一个帖子的id
		fout.close();*/
		indexWriter.commit();
		indexWriter.close();
	}

	/**
	 * the increment of memos index
	 * @param rs
	 * @return
	 * @throws IOException
	 * @throws SQLException
	 */
	public int memoIndexIncrement(List<RelativeMemo> memos) throws IOException,
			SQLException {
		Directory dire = FSDirectory.open(Paths.get(MEMOS_INDEX_PATH));
		IndexWriterConfig iwc = new IndexWriterConfig(new IKAnalyzer(true));
		iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
		IndexWriter indexWriter = new IndexWriter(dire, iwc);
		int rsId = -1;
		for(RelativeMemo memo : memos) {
			rsId = memo.getId();
			if (memo.getContent() == null) {
				continue;
			}
			Document doc = new Document();
			if (memo.getExperience() == null) {
				memo.setExperience("");
			}
			if (memo.getSalary() == null) {
				memo.setSalary("");
			}
			if (memo.getAddr() == null) {
				memo.setAddr("");
			}
			doc.add(new StringField(memoIdFieldName, String.valueOf(rsId), Store.YES));
			doc.add(new TextField(contentFieldName, memo.getContent(), Store.NO));
			doc.add(new StringField(experienceFieldName, memo.getExperience(), Store.YES));
			doc.add(new StringField(salaryFieldName, memo.getSalary(), Store.YES));
			doc.add(new StringField(addrFieldName, memo.getAddr(), Store.YES));
			indexWriter.addDocument(doc);
		}
		indexWriter.commit();
		indexWriter.close();
		return rsId;
	}

	/**
	 * the increment of projects index
	 * @param rs
	 * @return
	 * @throws IOException
	 * @throws SQLException
	 */
	public int prjIndexIncrement(List<Project> newPrjs) throws IOException, SQLException {
		Directory dire = FSDirectory.open(Paths.get(PRJS_INDEX_PATH));
		IndexWriterConfig iwc = new IndexWriterConfig(new IKAnalyzer(true));
		iwc.setOpenMode(IndexWriterConfig.OpenMode.CREATE_OR_APPEND);
		IndexWriter iw = new IndexWriter(dire, iwc);
		int rsId = -1;
		for(Project project : newPrjs) {
			rsId = project.getId();
			if (project.getName() == null || "".equals(project.getName())) {
				continue;
			}
			Document doc = new Document();
			String prjName = project.getName();
			doc.add(new StringField(prjIdFieldName, String.valueOf(rsId), Store.YES));
			Field prjNameField = new TextField(prjNameFieldName, prjName, Store.YES);
			if (prjName.getBytes().length == prjName.length() && prjName.replaceAll("\\d+"," ").indexOf(" ") == -1) {
				prjNameField.setBoost(6.0f);
			}
			doc.add(prjNameField);
			String prjTagsString = project.getTags();
			if (prjTagsString == null) {
				prjTagsString = "";
			}
			List<String> prjTagsList = Normalizer.tagsSegmentation(prjTagsString.toLowerCase());
			for(String prjTag : prjTagsList){
				doc.add(new StringField(prjTagsFieldName, prjTag, Store.NO));
			}
			iw.addDocument(doc);
		}
		iw.commit();
		iw.close();
		return rsId;
	}
	
}
